package com.lap.framework.generator.domain.valueobject;

import com.lap.framework.common.tool.Named;
import com.lap.framework.generator.infra.query.meta.ColumnMeta;
import com.lap.framework.generator.shared.enums.AnnotationType;
import com.lap.framework.generator.shared.enums.ValidationType;
import com.lap.framework.generator.shared.tool.TextUtil;
import java.util.*;
import lombok.*;

@Builder
@Data
public class FieldModel {

  // 基本字段属性（不可变）
  private final String columnName;
  private final String columnType;
  private final TypeModel typeModel;
  private final String fieldName;
  private final String comment;
  private final boolean nullable;

  // 配置相关属性（通过配置方法设置）
  private final boolean ignoreEntity;
  private final boolean dateField;
  private final boolean ignoreInsert;
  private final boolean ignoreUpdate;
  private final boolean ignoreCommand;

  // 验证相关属性（延迟初始化）
  private List<String> errorMessages;
  private List<String> annotations;

  /** 创建字段模型并应用配置 */
  public static FieldModel createFromColumn(
      ColumnMeta column, FieldConfig config, String parentCode) {
    FieldModelBuilder builder =
        FieldModel.builder()
            .columnName(column.getColumnName())
            .columnType(column.getDataType())
            .typeModel(column.getTypeModel())
            .fieldName(Named.lowerHump(column.getColumnName()))
            .comment(column.getComment())
            .nullable(column.isNullable());

    // 应用配置
    applyFieldConfigurations(builder, column, config, parentCode);

    return builder.build();
  }

  /** 应用字段配置 */
  private static void applyFieldConfigurations(
      FieldModelBuilder builder, ColumnMeta column, FieldConfig config, String parentCode) {
    String columnName = column.getColumnName();
    TypeModel typeModel = column.getTypeModel();

    // 设置忽略和特殊字段标记
    builder
        .ignoreEntity(config.isExcludedField(columnName))
        .dateField(config.isExcludedField(columnName) && JavaType.isDate(typeModel.javaType()))
        .ignoreInsert(config.isIgnoreInsertField(columnName))
        .ignoreUpdate(config.isIgnoreUpdateField(columnName))
        .ignoreCommand(config.isIgnoreCommandField(columnName));
  }

  /** 添加验证规则（在对象构建后调用） */
  public void addValidations(ValidationContext context) {
    if (context.isExcludedField(this.columnName)) {
      return;
    }

    addNotNullValidation(context);
    addLengthValidation(context);
  }

  /** 添加非空验证 */
  private void addNotNullValidation(ValidationContext context) {
    if (!isNullable()) {
      String i18nKey = getI18nKey(context.parentCode(), fieldName, ValidationType.REQUIRED);
      String annotation =
          JavaType.eqStr(typeModel.javaType())
              ? String.format(AnnotationType.NOT_BLANK.getValue(), i18nKey)
              : String.format(AnnotationType.NOT_NULL.getValue(), i18nKey);

      getAnnotations().add(annotation);
      getErrorMessages().add(String.format("%s=%s不能为空", i18nKey, TextUtil.resolveText(comment)));
    }
  }

  /** 添加长度验证 */
  private void addLengthValidation(ValidationContext context) {
    String i18nKey;
    String annotation;

    if (JavaType.eqNum(typeModel.javaType())) {
      i18nKey = getI18nKey(context.parentCode(), fieldName, ValidationType.RANGE);
      annotation =
          String.format(
              AnnotationType.NUMBER_RANGE.getValue(), typeModel.min(), typeModel.max(), i18nKey);
      getAnnotations().add(annotation);
      getErrorMessages()
          .add(String.format("%s=%s值在{min}和{max}间", i18nKey, TextUtil.resolveText(comment)));
    } else if (JavaType.eqStr(typeModel.javaType())) {
      i18nKey = getI18nKey(context.parentCode(), fieldName, ValidationType.MAX_LENGTH);
      annotation = String.format(AnnotationType.LENGTH.getValue(), typeModel.max(), i18nKey);
      getAnnotations().add(annotation);
      getErrorMessages()
          .add(String.format("%s=%s长度不能超过{max}", i18nKey, TextUtil.resolveText(comment)));
    }
  }

  // 辅助方法
  private String getI18nKey(String parentCode, String fieldCode, ValidationType suffixMessage) {
    return String.format("%s.%s.%s", parentCode, fieldCode, suffixMessage.getSuffix());
  }

  // 延迟初始化的getter方法
  public List<String> getAnnotations() {
    if (annotations == null) {
      annotations = new ArrayList<>();
    }
    return annotations;
  }

  public List<String> getErrorMessages() {
    if (errorMessages == null) {
      errorMessages = new ArrayList<>();
    }
    return errorMessages;
  }

  /** 获取Java类型代码 */
  public String getJavaType() {
    return Optional.ofNullable(typeModel)
        .map(TypeModel::javaType)
        .map(JavaType::getCode)
        .orElse(null);
  }

  /** 字段配置类 - 封装字段相关的配置信息 */
  public record FieldConfig(
      Set<String> excludeField,
      Set<String> ignoreInsert,
      Set<String> ignoreUpdate,
      Set<String> ignoreCommand) {

    public boolean isExcludedField(String columnName) {
      return excludeField.stream().anyMatch(item -> item.equalsIgnoreCase(columnName));
    }

    public boolean isIgnoreInsertField(String columnName) {
      return ignoreInsert.stream().anyMatch(columnName::equalsIgnoreCase);
    }

    public boolean isIgnoreUpdateField(String columnName) {
      return ignoreUpdate.stream().anyMatch(columnName::equalsIgnoreCase);
    }

    public boolean isIgnoreCommandField(String columnName) {
      return ignoreCommand.stream().anyMatch(columnName::equalsIgnoreCase)
          || excludeField.stream().anyMatch(columnName::equalsIgnoreCase);
    }
  }

  /** 验证上下文 - 封装验证所需的信息 */
  public record ValidationContext(String parentCode, Set<String> excludeField) {

    public boolean isExcludedField(String columnName) {
      return excludeField.stream().anyMatch(item -> item.equalsIgnoreCase(columnName));
    }
  }
}
